package sv.gob.mh.dgii.xml;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;


public class XmlResultSet implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private String xml;
	
	public XmlResultSet(ResultSet rs) throws SQLException {
		if (rs == null) {
			throw new NullPointerException();
		}
		Document document = build(rs);
		xml = document.asXML();			
	}
	
	public XmlResultSet(ResultSet rs, boolean grpByFst) throws SQLException {
		if (rs == null) {
			throw new NullPointerException();
		}
		Document document = buildCrossed(rs, grpByFst);
		xml = document.asXML();
	}	
	
	protected Document build(ResultSet rs) throws SQLException {
		ResultSetMetaData rsmd = rs.getMetaData();
		int intColCount = rsmd.getColumnCount();

		Document doc = DocumentHelper.createDocument();
        Element root = doc.addElement(XmlConstants.MAIN);
		Element columns = root.addElement(XmlConstants.COLUMNS);
		Element rows = root.addElement(XmlConstants.ROWS);
		
		int rowCount = 0;
		// get column names for the record set
		String[] columnName = new String[intColCount];
		for (int index = 0; index < intColCount; index++) {
			columnName[index] = rsmd.getColumnName(index + 1);
			Element column = columns.addElement(XmlConstants.COLUMN);
			column.addText(columnName[index]);
			column.addAttribute(XmlConstants.CLASS, rsmd.getColumnClassName(index + 1));
		}
		columns.addAttribute(XmlConstants.COL_ATT_COUNT, String.valueOf(intColCount));
		while (rs.next()) {
			Element row = rows.addElement(XmlConstants.ROW);
			for (int col = 1; col <= intColCount; col++) {
				String name = columnName[col - 1];
				String value = rs.getString(col);
				Element node = row.addElement(XmlConstants.COLUMN);
				node.addAttribute(XmlConstants.COL_ID, name);
				node.addAttribute(XmlConstants.COL_INDEX, Integer.toString(col));
				
				
				if (!rs.wasNull()) {
					node.addText(value.toString());
				}
			}
			rowCount++;
		}
		rows.addAttribute(XmlConstants.ROWS_ATT_COUNT, String.valueOf(rowCount));
		return doc;

	}	
	
	
	protected Document buildCrossed(ResultSet rs, boolean keepFirstColForGroupings) throws SQLException {
		ResultSetMetaData rsmd = rs.getMetaData();
		int intColCount = rsmd.getColumnCount();
		int intFinalColCount = keepFirstColForGroupings?3:2;
		String firstColName = "";
		String firstColValue = null;
		int rowCount = 0;
		Document doc = DocumentHelper.createDocument();
        Element root = doc.addElement(XmlConstants.MAIN);
		Element columns = root.addElement(XmlConstants.COLUMNS);
		
		Element rows = root.addElement(XmlConstants.ROWS);
		Element row = null;
		
		// get column names for the record set
		String[] columnName = new String[intColCount];
		// fill the columnNames array
		for (int index = 0 ; index < intColCount; index++) {
			columnName[index] = rsmd.getColumnName(index + 1);
			if(index == 0)
				firstColName = rsmd.getColumnName(index + 1);
		}
		//Exist two default elements for the crossed xml output, listed at:
		Element tempColumn = columns.addElement(XmlConstants.NAMING_COLUMN);
		tempColumn.addAttribute(XmlConstants.CLASS, XmlConstants.NAMING_COLUMN_CLASSATT);
		tempColumn = columns.addElement(XmlConstants.VALUE_COLUMN);
		tempColumn.addAttribute(XmlConstants.CLASS, XmlConstants.VALUE_COLUMN_CLASSATT);
		//The third one depends on keepFirstColForGroupings boolean parameter
		if(keepFirstColForGroupings){
			tempColumn = columns.addElement(firstColName);
			tempColumn.addAttribute(XmlConstants.CLASS, rsmd.getColumnClassName(1));
		}
		columns.addAttribute(XmlConstants.COL_ATT_COUNT, String.valueOf(intFinalColCount));
		while (rs.next()){
			for(int col = 1; col <= intColCount; col++){
				if(col != 1 || !keepFirstColForGroupings){
					row = rows.addElement(XmlConstants.ROW);
					Element node = row.addElement(XmlConstants.COLUMN);
					node.addAttribute(XmlConstants.COL_ID, XmlConstants.NAMING_COLUMN);
					node.addText(columnName[col-1]);
					node = row.addElement(XmlConstants.COLUMN);
					node.addAttribute(XmlConstants.COL_ID, XmlConstants.VALUE_COLUMN);
					if(!rs.wasNull())
						node.addText(rs.getString(col));
					if(keepFirstColForGroupings){
						//Adding the grouping Element (1st.)
						Element groupElement = row.addElement(XmlConstants.COLUMN);
						groupElement.addAttribute(XmlConstants.COL_ID, firstColName);
						if(firstColValue!=null)
							groupElement.addText(firstColValue);
					}
					rowCount++;
				}
				else{
					firstColValue = rs.getString(col);
				}
			}
		}
		rows.addAttribute(XmlConstants.ROWS_ATT_COUNT, String.valueOf(rowCount));
		return doc;
	}		
	

	public String getXml() {		
		return xml;
	}
	
	
}
